package com.eastedu.report.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.eastedu.common.enums.Section;
import com.eastedu.report.common.model.parameter.ReportExportParameter;
import com.eastedu.report.common.model.parameter.ReportGenerateParameter;
import com.eastedu.report.common.model.po.CooperativeSchoolPO;
import com.eastedu.report.common.util.ReportUtil;
import com.eastedu.report.mapper.CooperativeSchoolMapper;
import com.eastedu.report.principal.assemble.ReportDataAssembly;
import com.eastedu.report.service.PrincipalMonthlyReportService;
import com.eastedu.report.service.ReportExportTaskService;
import com.eastedu.template.core.lifrcycle.ReportExportCycle;
import com.eastedu.template.exception.ReportGenerateCallback;
import com.eastedu.template.model.ReportDataContainer;
import com.eastedu.template.model.ReportResult;
import com.eastedu.template.model.SchoolReportFileData;
import com.google.common.collect.Maps;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * The type Principal monthly report service.
 *
 * @author superman
 */
@Service
public class PrincipalMonthlyReportServiceImpl implements PrincipalMonthlyReportService {
    private final ReportExportCycle reportExportCycle;
    private final List<ReportDataAssembly> reportDataAssemblies;
    private final CooperativeSchoolMapper cooperativeSchoolMapper;
    private final ReportExportTaskService reportExportTaskService;

    /**
     * Instantiates a new Principal monthly report service.
     *
     * @param reportExportCycle       the report export cycle
     * @param reportDataAssemblies    the report data assemblies
     * @param cooperativeSchoolMapper the cooperative school mapper
     * @param reportExportTaskService the report export task service
     */
    public PrincipalMonthlyReportServiceImpl(ReportExportCycle reportExportCycle,
                                             List<ReportDataAssembly> reportDataAssemblies,
                                             CooperativeSchoolMapper cooperativeSchoolMapper,
                                             ReportExportTaskService reportExportTaskService) {
        this.reportExportCycle = reportExportCycle;
        this.reportDataAssemblies = reportDataAssemblies;
        this.cooperativeSchoolMapper = cooperativeSchoolMapper;
        this.reportExportTaskService = reportExportTaskService;
    }

    @Override
    public List<ReportResult> generate(ReportExportParameter parameter) {

        LambdaQueryWrapper<CooperativeSchoolPO> wrapper = Wrappers.<CooperativeSchoolPO>lambdaQuery()
                .eq(Objects.nonNull(parameter.getSchoolGroupId()), CooperativeSchoolPO::getSchoolGroupId, parameter.getSchoolGroupId())
                .eq(Objects.nonNull(parameter.getSchoolGuid()), CooperativeSchoolPO::getSchoolGuid, parameter.getSchoolGuid())
                .eq(Objects.nonNull(parameter.getSection()), CooperativeSchoolPO::getSectionCode, parameter.getSection())
                .eq(Objects.nonNull(parameter.getCodeType()), CooperativeSchoolPO::getCodeType, parameter.getCodeType())
                .eq(Objects.nonNull(parameter.getDateCode()), CooperativeSchoolPO::getDateCode, parameter.getDateCode());

        List<CooperativeSchoolPO> pos = cooperativeSchoolMapper.selectList(wrapper);
        Map<ReportGenerateParameter, List<CooperativeSchoolPO>> parameters = pos.parallelStream().collect(Collectors.groupingBy(po -> ReportGenerateParameter.builder()
                                                                                                                  .schoolGroupId(po.getSchoolGroupId())
                                                                                                                  .schoolGuid(po.getSchoolGuid())
                                                                                                                  .section(po.getSectionCode())
                                                                                                                  .schoolName(po.getSchoolName())
                                                                                                                  .sectionName(Section.getByCode(po.getSectionCode()).getName())
                                                                                                                  .codeType(po.getCodeType())
                                                                                                                  .dateCode(po.getDateCode())
                                                                                                                  .debug(parameter.isDebug())
                                                                                                                  .build()
                                                                                                          )
        );
        return parameters.entrySet()
                .stream()
                .map((entry) -> {
                    ReportGenerateParameter generateParameter = entry.getKey();
                    List<CooperativeSchoolPO> schools = entry.getValue();
                    List<String> schoolPeriods = schools.parallelStream().map(CooperativeSchoolPO::getSchoolPeriod).distinct().collect(Collectors.toList());
                    List<String> subjects = schools.parallelStream().map(CooperativeSchoolPO::getSubjectCode).distinct().collect(Collectors.toList());
                    Map<String, Object> data = Maps.newHashMap();
                    // 填充公共报表数据
                    ReportUtil.fillCommonReportData(data, generateParameter);
                    for (ReportDataAssembly reportDataAssembly : reportDataAssemblies) {
                        data.putAll(reportDataAssembly.assemble(generateParameter, schoolPeriods, subjects));
                    }

                    ReportResult result = reportExportTaskService.create(generateParameter);
                    ReportDataContainer container = ReportDataContainer.builder()
                            .taskId(result.getTaskId())
                            .parameter(generateParameter)
                            .data(data)
                            .templateCode("principal_monthly_report_lzz")
                            .debug(parameter.isDebug())
                            .build();
                    ReportGenerateCallback callback = new ReportGenerateCallback() {
                        private final ReportGenerateCallback callback = new DefaultReportGenerateCallback();

                        @Override
                        public void success(String taskId, ReportResult result) {
                            this.callback.success(taskId, result);
                            reportExportTaskService.finish(taskId, result);
                        }

                        @Override
                        public void failure(String taskId, Throwable throwable) {
                            this.callback.failure(taskId, throwable);
                            reportExportTaskService.failure(taskId, throwable);
                        }
                    };
                    reportExportCycle.start(container, callback);
                    return result;
                })
                .collect(Collectors.toList());

    }

    @Override
    public ReportResult getReport(String taskId) {
        return reportExportTaskService.get(taskId);
    }

    @Override
    public SchoolReportFileData getReportForCompress(ReportExportParameter parameter) {
        return reportExportTaskService.getReportForCompress(parameter);
    }
}
